#include "nuklear.h"
#include "nuklear_internal.h"

/* ===============================================================
 *
 *                              WIDGET
 *
 * ===============================================================*/
NK_API nk_rect
nk_widget_bounds(nk_context* ctx) {
  nk_rect bounds;
  NK_ASSERT(ctx);
  NK_ASSERT(ctx->current);
  if (!ctx || !ctx->current)
    return nk_make_rect(0, 0, 0, 0);
  nk_layout_peek(&bounds, ctx);
  return bounds;
}
NK_API nk_vec2
nk_widget_position(nk_context* ctx) {
  nk_rect bounds;
  NK_ASSERT(ctx);
  NK_ASSERT(ctx->current);
  if (!ctx || !ctx->current)
    return nk_make_vec2(0, 0);

  nk_layout_peek(&bounds, ctx);
  return nk_make_vec2(bounds.x, bounds.y);
}
NK_API nk_vec2
nk_widget_size(nk_context* ctx) {
  nk_rect bounds;
  NK_ASSERT(ctx);
  NK_ASSERT(ctx->current);
  if (!ctx || !ctx->current)
    return nk_make_vec2(0, 0);

  nk_layout_peek(&bounds, ctx);
  return nk_make_vec2(bounds.w, bounds.h);
}
NK_API float nk_widget_width(nk_context* ctx) {
  nk_rect bounds;
  NK_ASSERT(ctx);
  NK_ASSERT(ctx->current);
  if (!ctx || !ctx->current)
    return 0;

  nk_layout_peek(&bounds, ctx);
  return bounds.w;
}
NK_API float nk_widget_height(nk_context* ctx) {
  nk_rect bounds;
  NK_ASSERT(ctx);
  NK_ASSERT(ctx->current);
  if (!ctx || !ctx->current)
    return 0;

  nk_layout_peek(&bounds, ctx);
  return bounds.h;
}
NK_API nk_bool
nk_widget_is_hovered(nk_context* ctx) {
  nk_rect c, v;
  nk_rect bounds;
  NK_ASSERT(ctx);
  NK_ASSERT(ctx->current);
  if (!ctx || !ctx->current || ctx->active != ctx->current)
    return 0;

  c = ctx->current->layout->clip;
  c.x = (float)((int)c.x);
  c.y = (float)((int)c.y);
  c.w = (float)((int)c.w);
  c.h = (float)((int)c.h);

  nk_layout_peek(&bounds, ctx);
  nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h);
  if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h))
    return 0;
  return nk_input_is_mouse_hovering_rect(&ctx->input, bounds);
}
NK_API nk_bool
nk_widget_is_mouse_clicked(nk_context* ctx, nk_buttons btn) {
  nk_rect c, v;
  nk_rect bounds;
  NK_ASSERT(ctx);
  NK_ASSERT(ctx->current);
  if (!ctx || !ctx->current || ctx->active != ctx->current)
    return 0;

  c = ctx->current->layout->clip;
  c.x = (float)((int)c.x);
  c.y = (float)((int)c.y);
  c.w = (float)((int)c.w);
  c.h = (float)((int)c.h);

  nk_layout_peek(&bounds, ctx);
  nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h);
  if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h))
    return 0;
  return nk_input_mouse_clicked(&ctx->input, btn, bounds);
}
NK_API nk_bool
nk_widget_has_mouse_click_down(nk_context* ctx, nk_buttons btn, nk_bool down) {
  nk_rect c, v;
  nk_rect bounds;
  NK_ASSERT(ctx);
  NK_ASSERT(ctx->current);
  if (!ctx || !ctx->current || ctx->active != ctx->current)
    return 0;

  c = ctx->current->layout->clip;
  c.x = (float)((int)c.x);
  c.y = (float)((int)c.y);
  c.w = (float)((int)c.w);
  c.h = (float)((int)c.h);

  nk_layout_peek(&bounds, ctx);
  nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h);
  if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h))
    return 0;
  return nk_input_has_mouse_click_down_in_rect(&ctx->input, btn, bounds, down);
}
NK_API nk_widget_layout_states
nk_widget(nk_rect* bounds, const nk_context* ctx) {
  nk_rect c, v;
  nk_window* win;
  nk_panel* layout;
  const nk_input* in;

  NK_ASSERT(ctx);
  NK_ASSERT(ctx->current);
  NK_ASSERT(ctx->current->layout);
  if (!ctx || !ctx->current || !ctx->current->layout)
    return NK_WIDGET_INVALID;

  /* allocate space and check if the widget needs to be updated and drawn */
  nk_panel_alloc_space(bounds, ctx);
  win = ctx->current;
  layout = win->layout;
  in = &ctx->input;
  c = layout->clip;

  /*  if one of these triggers you forgot to add an `if` condition around either
        a window, group, popup, combobox or contextual menu `begin` and `end` block.
        Example:
            if (nk_begin(...) {...} nk_end(...); or
            if (nk_group_begin(...) { nk_group_end(...);} */
  NK_ASSERT(!(layout->flags & NK_WINDOW_MINIMIZED));
  NK_ASSERT(!(layout->flags & NK_WINDOW_HIDDEN));
  NK_ASSERT(!(layout->flags & NK_WINDOW_CLOSED));

  /* need to convert to int here to remove floating point errors */
  bounds->x = (float)((int)bounds->x);
  bounds->y = (float)((int)bounds->y);
  bounds->w = (float)((int)bounds->w);
  bounds->h = (float)((int)bounds->h);

  c.x = (float)((int)c.x);
  c.y = (float)((int)c.y);
  c.w = (float)((int)c.w);
  c.h = (float)((int)c.h);

  nk_unify(&v, &c, bounds->x, bounds->y, bounds->x + bounds->w, bounds->y + bounds->h);
  if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds->x, bounds->y, bounds->w, bounds->h))
    return NK_WIDGET_INVALID;
  if (!NK_INBOX(in->mouse.pos.x, in->mouse.pos.y, v.x, v.y, v.w, v.h))
    return NK_WIDGET_ROM;
  return NK_WIDGET_VALID;
}
NK_API nk_widget_layout_states
nk_widget_fitting(nk_rect* bounds, nk_context* ctx,
                  nk_vec2 item_padding) {
  /* update the bounds to stand without padding  */
  nk_widget_layout_states state;
  NK_UNUSED(item_padding);

  NK_ASSERT(ctx);
  NK_ASSERT(ctx->current);
  NK_ASSERT(ctx->current->layout);
  if (!ctx || !ctx->current || !ctx->current->layout)
    return NK_WIDGET_INVALID;

  state = nk_widget(bounds, ctx);
  return state;
}
NK_API void nk_spacing(nk_context* ctx, int cols) {
  nk_window* win;
  nk_panel* layout;
  nk_rect none;
  int i, index, rows;

  NK_ASSERT(ctx);
  NK_ASSERT(ctx->current);
  NK_ASSERT(ctx->current->layout);
  if (!ctx || !ctx->current || !ctx->current->layout)
    return;

  /* spacing over row boundaries */
  win = ctx->current;
  layout = win->layout;
  index = (layout->row.index + cols) % layout->row.columns;
  rows = (layout->row.index + cols) / layout->row.columns;
  if (rows) {
    for (i = 0; i < rows; ++i)
      nk_panel_alloc_row(ctx, win);
    cols = index;
  }
  /* non table layout need to allocate space */
  if (layout->row.type != NK_LAYOUT_DYNAMIC_FIXED &&
      layout->row.type != NK_LAYOUT_STATIC_FIXED) {
    for (i = 0; i < cols; ++i)
      nk_panel_alloc_space(&none, ctx);
  }
  layout->row.index = index;
}
